#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>

template<class T>
class BlockQueue
{
    static const int defaultnum=5;
public:
    //默认构造函数
    BlockQueue(int maxcap=defaultnum):maxcap_(maxcap)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&c_cond_,nullptr);
        pthread_cond_init(&p_cond_,nullptr);
        low_water=maxcap_/3;
        high_water=(maxcap_*2)/3;
    }

    T pop()
    {
        pthread_mutex_lock(&mutex_);
        if(q_.size()==0)
        {
            pthread_cond_wait(&c_cond_,&mutex_);
            //用同一把锁不同的条件变量，区别生产和消费队列
        }

        T out=q_.front();
        q_.pop();
        if(q_.size()<low_water) pthread_cond_signal(&p_cond_);//唤醒数据
        pthread_mutex_unlock(&mutex_);
        return out;
    }

    void push(const T &in)
    {
        pthread_mutex_lock(&mutex_);
        if(q_.size()==maxcap_)//判断必须在加锁之后！！！因为判断就是在访问临界资源
        {
            pthread_cond_wait(&p_cond_,&mutex_);
            //调用的时候要自动释放锁
        }

        //1.队列没有满  2.被唤醒
        q_.push(in);
        if(q_.size()>high_water) pthread_cond_signal(&c_cond_);//唤醒数据
        pthread_mutex_unlock(&mutex_);
        //不是你想生成就可以生产的？ -> 生产的条件要满足
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&c_cond_);
        pthread_cond_destroy(&p_cond_);
    }

private:
    std::queue<T> q_;//STL不是线程安全的
    //int mincap_;
    int maxcap_;//队列极值
    pthread_mutex_t mutex_;//添加一把锁
    pthread_cond_t c_cond_;//添加条件变量，实现线程同步
    pthread_cond_t p_cond_;
    int low_water;//水位线
    int high_water;
};